<script setup lang="ts">
import {computed, h, ref, type VNode, watch, watchEffect} from 'vue';

import {usePagination} from '@/hooks';
import {EmptyIcon, Grip, listIcons} from '@/plugins/iconify';
import {$t} from '@/locales/effects';
import {
  Button,
  Pagination,
  PaginationEllipsis,
  PaginationFirst,
  PaginationLast,
  PaginationList,
  PaginationListItem,
  PaginationNext,
  PaginationPrev,
  JcxIcon,
  JcxIconButton,
  JcxPopover,
} from '@/components/common/shadcn';

import {refDebounced} from '@vueuse/core';

interface Props {
  pageSize?: number;
  prefix?: string;
  /**
   * 图标列表
   */
  icons?: string[];
  /** Input组件 */
  inputComponent?: VNode;
  /** 图标插槽名，预览图标将被渲染到此插槽中 */
  iconSlot?: string;
  /** input组件的值属性名称 */
  modelValueProp?: string;
  /** 图标样式 */
  iconClass?: string;
}

const props = withDefaults(defineProps<Props>(), {
  prefix: 'ant-design',
  pageSize: 36,
  icons: () => [],
  inputComponent: () => h('div'),
  iconSlot: 'default',
  iconClass: 'size-4',
  modelValueProp: 'value',
});

const emit = defineEmits<{
  change: [string];
}>();

const modelValue = defineModel({default: '', type: String});

const visible = ref(false);
const currentSelect = ref('');
const currentPage = ref(1);
const keyword = ref('');
const keywordDebounce = refDebounced(keyword, 300);
const currentList = computed(() => {
  try {
    if (props.prefix) {
      const icons = listIcons('', props.prefix);
      if (icons.length === 0) {
        console.warn(`No icons found for prefix: ${props.prefix}`);
      }
      return icons;
    } else {
      return props.icons;
    }
  } catch (error) {
    console.error('Failed to load icons:', error);
    return [];
  }
});

const showList = computed(() => {
  return currentList.value.filter((item) =>
      item.includes(keywordDebounce.value),
  );
});

const {paginationList, total, setCurrentPage} = usePagination(
    showList,
    props.pageSize,
);

watchEffect(() => {
  currentSelect.value = modelValue.value;
});

watch(
    () => currentSelect.value,
    (v) => {
      emit('change', v);
    },
);

const handleClick = (icon: string) => {
  currentSelect.value = icon;
  modelValue.value = icon;
  close();
};

const handlePageChange = (page: number) => {
  currentPage.value = page;
  setCurrentPage(page);
};

function toggleOpenState() {
  visible.value = !visible.value;
}

function open() {
  visible.value = true;
}

function close() {
  visible.value = false;
}

function onKeywordChange(v: string) {
  keyword.value = v;
}

const searchInputProps = computed(() => {
  return {
    placeholder: $t('ui.iconPicker.search'),
    [props.modelValueProp]: keyword.value,
    [`onUpdate:${props.modelValueProp}`]: onKeywordChange,
    class: 'mx-2',
  };
});

defineExpose({toggleOpenState, open, close});
</script>
<template>
  <JcxPopover
      v-model:open="visible"
      :content-props="{ align: 'end', alignOffset: -11, sideOffset: 8 }"
      content-class="p-0 pt-3"
  >
    <template #trigger>
      <component
          :is="inputComponent"
          :[modelValueProp]="currentSelect"
          :placeholder="$t('ui.iconPicker.placeholder')"
      >
        <template #[iconSlot]>
          <JcxIcon :icon="currentSelect || Grip" class="size-4"/>
        </template>
      </component>
    </template>
    <div class="mb-2 flex w-full">
      <component :is="inputComponent" v-bind="searchInputProps"/>
    </div>

    <template v-if="paginationList.length > 0">
      <div class="grid max-h-[360px] w-full grid-cols-6 justify-items-center">
        <JcxIconButton
            v-for="(item, index) in paginationList"
            :key="index"
            :tooltip="item"
            tooltip-side="top"
            @click="handleClick(item)"
        >
          <JcxIcon
              :class="{
              'text-primary transition-all': currentSelect === item,
            }"
              :icon="item"
          />
        </JcxIconButton>
      </div>
      <div
          v-if="total >= pageSize"
          class="flex-center flex justify-end overflow-hidden border-t py-2 pr-3"
      >
        <Pagination
            :items-per-page="36"
            :sibling-count="1"
            :total="total"
            show-edges
            size="small"
            @update:page="handlePageChange"
        >
          <PaginationList
              v-slot="{ items }"
              class="flex w-full items-center gap-1"
          >
            <PaginationFirst class="size-5"/>
            <PaginationPrev class="size-5"/>
            <template v-for="(item, index) in items">
              <PaginationListItem
                  v-if="item.type === 'page'"
                  :key="index"
                  :value="item.value"
                  as-child
              >
                <Button
                    :variant="item.value === currentPage ? 'default' : 'outline'"
                    class="size-5 p-0 text-sm"
                >
                  {{ item.value }}
                </Button>
              </PaginationListItem>
              <PaginationEllipsis
                  v-else
                  :key="item.type"
                  :index="index"
                  class="size-5"
              />
            </template>
            <PaginationNext class="size-5"/>
            <PaginationLast class="size-5"/>
          </PaginationList>
        </Pagination>
      </div>
    </template>

    <template v-else>
      <div class="flex-col-center text-muted-foreground min-h-[150px] w-full">
        <EmptyIcon class="size-10"/>
        <div class="mt-1 text-sm">{{ $t('common.noData') }}</div>
      </div>
    </template>
  </JcxPopover>
</template>
